/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import fileio from '@ohos.file.fs';
import http from '@ohos.net.http';
import request from '@ohos.request';
import { PriorityAsyncTask } from '../task/PriorityAsyncTask'
import { HttpRedirectHandler } from './callback/HttpRedirectHandler'
import { HttpRequest } from './client/HttpRequest'
import { HttpMethod } from './client/HttpMethod'
import { RequestCallBack } from './callback/RequestCallBack'
import { HttpCache } from './HttpCache'
import { Stated } from './Stated'
import { ResponseInfo } from './ResponseInfo'
import { UploadConfig } from './UploadConfig'
import { ReConnect } from './ReConnect'
import { GlobalContext } from '../GlobalContext';
import { Context } from '@ohos.abilityAccessCtrl';

export class HttpHandler<T> extends PriorityAsyncTask {
    public InterceptorCallback: ESObject = null
    private httpRedirectHandler: HttpRedirectHandler;
    private connectTimeout = 60000
    private readTimeout = 60000
    private retryTimes: number = 3
    private charset: string;
    private callback: RequestCallBack<T>;
    private state = Stated.WAITING;
    private expiry = HttpCache.prototype.getDefaultExpiryTime();
    private global: GlobalContext =GlobalContext.getContext()

    constructor(charset: string, callback: RequestCallBack<T>) {
        super()
        this.charset = charset;
        this.callback = callback;
    }

    public setHttpRedirectHandler(httpRedirectHandler: HttpRedirectHandler) {
        if (httpRedirectHandler != null) {
            this.httpRedirectHandler = httpRedirectHandler;
        }
    }

    public setExpiry(expiry: number) {
        this.expiry = expiry;
    }

    public setRetryTimes(count: number) {
        this.retryTimes = count;
    }

    public setTimeout(timeout: number) {
        this.connectTimeout = timeout
    }

    public setSoTimeout(timeout: number) {
        this.readTimeout = timeout
    }

    public setInterceptor(callback?: Function) {
        this.InterceptorCallback = callback
    }

    doInBackground(params: HttpRequest) {
        if (this.InterceptorCallback != null) {
            this.InterceptorCallback(params)
        } else {
            if (params.getMethod() == HttpMethod.GET.valueOf()) {
                this.sendRequest(params)
            } else if (params.getMethod() == HttpMethod.POST.valueOf()) {
                this.sendRequestPost(params)
            }
        }
    }

    doInBackgroundForPixelMap() {

    }

    doInBackgroundDownload(params: HttpRequest, target: string) {
        let that = this
        let path = this.global.getValue('filesDir') + target;
        let exits = fileio.accessSync(path);
        if (exits){
            fileio.unlinkSync(path)
        }
        request.downloadFile(this.global.getValue('context') as Context, {
            url: params.getURIBuilder().getPath(),
            filePath: path
        }).then((loadTask) => {
                loadTask.on('progress', function download_callback(receivedSize, totalSize) {
                    that.callback.onDownloadProgress(receivedSize, totalSize)
                });
                loadTask.on('complete', function callback() {
                    that.callback.onDownloadSuccess()
                })
                loadTask.on('fail',err => {
                    that.callback.onError(err)
                })
            })
            .catch((err) => {
                that.callback.onError(err)
            })
    }

    doInBackgroundUpload(uploadConfig: UploadConfig) {
        let that = this
        request.uploadFile(this.global.getValue('context') as Context, {
            url: uploadConfig.url,
            method: uploadConfig.method,
            header: uploadConfig.header,
            files: uploadConfig.files,
            data: uploadConfig.data
        }).then((uploadTask) => {
                uploadTask.on('progress', function callback(uploadedSize, totalSize) {
                    that.callback.onProgress( uploadedSize,totalSize)
                });
                uploadTask.on('complete', function callback() {
                    that.callback.onSuccess(null);
                })
                uploadTask.on('fail', err => {
                    that.callback.onError(err)
                })
            })
            .catch((err) => {
                that.callback.onError(err)
            })
    }

    // 执行get请求
    private sendRequest(params: HttpRequest) {
        let headersJson = {};
        for (let [k, v] of params.getURIBuilder().getHeaders()) {
            headersJson[k] = v;
        }
        // 每一个httpRequest对应一个http请求任务，不可复用
        let options = {
            method: params.getMethod(),
            header: headersJson,
            connectTimeout: this.connectTimeout,
            readTimeout: this.readTimeout,
        }

        ReConnect.prototype.request(new Date().getTime(), params.getURIBuilder().getPath(), options, this.retryTimes, (err, data) => {
            if (!err) {
                if (data.responseCode == 200) {
                    this.handleResponse(data)
                } else {
                    this.callback.onFailure()
                }
            } else {
                this.callback.onError(err)
            }
        })
    }

    // 执行post请求
    private sendRequestPost(params: HttpRequest) {
        let headersJson = {};
        let paramsJson = {};
        for (let [k, v] of params.getURIBuilder().getHeaders()) {
            headersJson[k] = v;
        }
        for (let [k, v] of params.getURIBuilder().getQueryParams()) {
            paramsJson[k] = v;
        }
        // 每一个httpRequest对应一个http请求任务，不可复用
        let options = {
            method: http.RequestMethod.POST,
            header: headersJson,
            extraData: paramsJson,
            connectTimeout: this.connectTimeout,
            readTimeout: this.readTimeout,
        }
        ReConnect.prototype.request(new Date().getTime(), params.getURIBuilder().getPath(), options, this.retryTimes, (err, data) => {
            if (!err) {
                if (data.responseCode == 200) {
                    this.handleResponse(data)
                } else {
                    this.callback.onFailure()
                }
            } else {
                this.callback.onError(err)
            }
        })
    }

    private handleResponse(response: http.HttpResponse): ResponseInfo<T> {
        if (response == null) {
            throw new Error("response is null");
        }
        var responseInfo = new ResponseInfo<T>(response, response.result, false);
        this.callback.onSuccess(responseInfo);
        return responseInfo;
    }
}
